<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>签名</title>
  <style>
    * {
      padding: 0;
      margin: 0;
    }

    #canvas {
      border: 2px dotted #ccc;
      background-repeat: no-repeat;
      background-size: 80px;
    }

  </style>
</head>

<body>
  <div class="con-box">
    <canvas id="canvas" width="600px" height="400px"></canvas>
    <input type="range" class="range" min="1" max="30" value="1" id="range">
    <button id="revoke">撤销</button>
    <button id="save">保存</button>
    <button id="reset">重置</button>
  </div>
</body>
<script>
  let range = document.querySelector("#range");

  // 获取canvas元素的DOM对象 
  const canvas = document.getElementById('canvas')
  // 获取渲染上下文和它的绘画功能
  const ctx = canvas.getContext('2d')
  // 笔画内容的颜色，一般为黑色
  ctx.strokeStyle = '#000'

  let historyArr = [] //保存所有的操作
  let currentPath = null;

  let revoke = document.querySelector("#revoke");

  // 注册鼠标按下事件
  canvas.addEventListener('mousedown', mousedownFun)

  // 鼠标移出canvas所在的区域事件-处理鼠标移出canvas所在区域后
  // 然后移入不按下鼠标也可以绘制笔画
  canvas.addEventListener('mouseout', e => {
    // 移除移动事件
    canvas.removeEventListener('mousemove', mousemoveFun)
  })

  // 按下事件
  function mousedownFun(e) {
    console.log('按下', e.pageX, e.pageY)
    // 开始本次绘画(与画笔大小设置有关)
    ctx.beginPath();
    // 设置画笔的粗细
    ctx.lineWidth = range.value || 1
    // 获取按下的那一刻鼠标的坐标,同时移动画笔
    ctx.moveTo(e.pageX, e.pageY)
    // 注册移动事件
    canvas.addEventListener('mousemove', mousemoveFun)
    // 注册抬起事件
    canvas.addEventListener('mouseup', mouseupFun)

    // 记录当前笔画起始点的特征(颜色 粗细 位置)
    currentPath = {
      color: ctx.strokeStyle,
      width: ctx.lineWidth,
      points: [{ x: e.offsetX, y: e.offsetY }]
    }
  }

  // 移动事件
  function mousemoveFun(e) {
    console.log('移动')
    // 使用直线连接路径的终点 x，y 坐标的方法（并不会真正地绘制）
    ctx.lineTo(e.pageX, e.pageY)

    currentPath.points.push({ x: e.offsetX, y: e.offsetY });

    // 使用 stroke() 方法真正地画线
    ctx.stroke()
  }

  // 抬起事件
  function mouseupFun(e) {
    console.log('抬起')
    historyArr.push(currentPath);
    // 结束本次绘画(与画笔大小设置有关)
    ctx.closePath();
    // 移除移动事件
    canvas.removeEventListener('mousemove', mousemoveFun)
    // 移除抬起事件
    canvas.removeEventListener('mouseup', mouseupFun)
  }

  // 画所有的路径
  function drawPaths(paths) {
    console.log(11, paths)
    paths.forEach(path => {
      ctx.beginPath();
      ctx.strokeStyle = path.color;
      ctx.lineWidth = path.width;
      ctx.moveTo(path.points[0].x, path.points[0].y);
      // path.points.slice(1) 少画 与  path.points 区别是少画一笔和正常笔数
      console.log('path', path)
      path.points.slice(1).forEach(point => {
        ctx.lineTo(point.x, point.y);
      });
      ctx.stroke();
    });
  }

  // 撤退
  document.getElementById("revoke").addEventListener("click", () => {
    if (historyArr.length === 0) return;
    // 删除最后一条的记录
    historyArr.pop()
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    drawPaths(historyArr);
  })

  // 重置
  document.getElementById("reset").addEventListener("click", () => {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
  })

  // 保存
  document.getElementById("save").addEventListener("click", () => {
    let imgURL = canvas.toDataURL({ format: "image/png", quality: 1, width: 600, height: 400 });
    let link = document.createElement('a');
    link.download = "tupian";
    link.href = imgURL;
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
  })
</script>

</html>
